// isInit是启用账套
const tools = require("../../tools/tool");
const {db, QueryTypes, Op} = require("../../models/db");
const tool = require("../../tools/tool");
// 审核/退审票据后更新库存余额
// type='init'|'recal'|'cal'
const updateInventory = async (tenantId = 0,billId=0, type='',isWaste = 0, invId=0 ) => {
    let sql = `exec updateInventory @tenantId=${tenantId}, @invId=${invId},@type='${type}',@billId=${billId},@isWaste=${isWaste} `
    await db.query(sql, {type: QueryTypes.UPDATE})
}
// 设置明细商品数据中的辅助数量
const updateAssQty = async (ctx) => {
    let body = ctx.request.body
    let tid = ctx.user.tenantId
    let transType = ctx.request.body.transType
    if ([150601,150602,150603,150501,150502,150706,150806,153403].indexOf(transType) !== -1 ) {
        let arr = []
        let infos = body.infos
        if(transType === 153403) {
            infos = body.invoiceInfoYs
        }
        for (let i = 0; i < infos.length; i++) {
            let row = infos[i]
            if(row.invId) {
                arr.push(`select ${row.invId} invId,${row.calNum} calNum,${row.spec} spec, '${row.unit}' unit ,${tools.multiply(row.qty,row.calNum)} qty`)
            }
        }
        if(arr.length > 0) {
            let sql = ` select a.*,b.spec oldSpec,b.unit1,b.unit2,b.name invName from (${arr.join(' union all ')}) a inner join v_goods b on a.invId=b.id and b.tenantId=${tid}`
            let list = await db.query(sql, {type: QueryTypes.SELECT})
            if(list.length !== arr.length) throw Error('商品档案错误')
            for (let i = 0; i < list.length; i++) {
                let row = list[i]
                if(row.spec !== row.oldSpec) throw Error(`商品规格设置错误，规格${row.spec} 不等于 ${row.oldSpec}`)
                if(tools.xe.toNumber(row.qty) === 0) throw Error(infos[i].invName + '商品数量不能等于 0')
                if(row.qty.toString().split('.').length > 1) throw Error(row.invName + '最小单位数量不能是小数')
                if(transType === 153403) {
                    ctx.request.body.invoiceInfoYs[i].assQty = tools.calAssQty(row.qty,row.spec,row.unit1, row.unit2)
                }
                else {
                    ctx.request.body.infos[i].assQty = tools.calAssQty(row.qty,row.spec,row.unit1, row.unit2)
                }
            }
        }
        else {
            throw Error('没有明细数据')
        }
    }
}
// 检测库存
const detectStock = async (billId, isWaste) => {
    // 本次业务票据出库的数量
    let sql = `
        with bills as (
            select tenantId,locationId,invId,sum(qtyReal*calNum) outC,transType,invName ,spec
            from v_main_info  where  iid=${billId} group by tenantId, locationId, invId,  transType, invName, spec
        )
        select a.tenantId, a.locationId, a.invId, a.outC, a.transType, a.invName, a.spec,isnull(b.lastCount,0) leftC from bills a  
            left join inventory b on a.tenantId=b.tenantId and a.locationId=b.locationId and a.invId=b.invId 
        `
    let list = await db.query(sql, {type: QueryTypes.SELECT})
    if(list.length > 0) {
        for (let i = 0; i < list.length; i++) {
            let row = list[i]
            let leftC = tools.xe.toNumber(row.leftC)
            let outC = tools.xe.toNumber(row.outC)
            let transType = tools.xe.toNumber(row.transType)
            let left = tools.xe.divide(leftC,row.spec)
            // 作废
            if(transType === 150601 || transType === 150603) {
                if(isWaste) {

                }
                else {
                    if(leftC < outC) {
                        throw Error(`【${list[i].invName}】 库存不足,结存 ${left} `)
                    }
                }
            }
            if(transType === 150806) {
                if(isWaste) {

                }
                else {
                    if(leftC < outC) {
                        throw Error(`【${list[i].invName}】 库存不足,结存 ${left}`)
                    }
                }
            }
        }
    }
}
// 检测业务单据收付款金额是否超过

const setBillNo = async (tenantId, transType) => {
    let billDate = tools.getDay()
    if (!transType) throw Error('未传入票据类型')
    let ymd = tools.getDay('',0,'DAY','YYYYMMDD')
    let prefix = '';
    if (transType === 150501) {
        prefix = 'CG'; // 采购
    }
    if (transType === 150502) {
        prefix = 'CT'; // 采退
    }
    if (transType === 150601) {
        prefix = 'XS'; // 销售
    }
    if (transType === 150602) {
        prefix = 'XT'; // 销退
    }
    if (transType === 150603) {
        prefix = 'XH'; // 换货
    }
    if (transType === 150706) {
        prefix = 'QTRK'; // 其它入库
    }
    if (transType === 150806) {
        prefix = 'QTCK'; // 其它出库
    }
    if (transType === 153001) {
        prefix = 'SK'; // 收款
    }
    if (transType === 153401) {
        prefix = 'SR'; // 其他收入
    }
    if (transType === 153101) {
        prefix = 'FK'; // 付款
    }
    if (transType === 153201) {
        prefix = 'HX'; // 核销单
    }
    if (transType === 153402) {
        prefix = 'ZC'; // 其他支出
    }
    if (transType === 153403) {
        prefix = 'YSG';
    }
    if (transType === 153407) {
        prefix = 'YSK'; // 预收钱  不关联商品
    }
    if (transType === 153404) {
        prefix = 'YS'; //应收款
    }
    if (transType === 153405) {
        prefix = 'YF'; // 应付
    }
    if (transType === 153406) {
        prefix = 'YFK'; // 员工支出
    }
    if (transType === 160001) {
        prefix = 'ZZ'; // 银行转账
    }
    if (transType === 190001) {
        prefix = 'PZ'; // 凭证
    }
    if (transType === 180001) {
        prefix = 'PD'; // 派单收款
    }
    if (!prefix) {
        throw Error('票号生成失败')
    }
    try {
        if(tenantId !== 16) {
            prefix += '-'
        }
        if (transType === 190001) {
            let card = await db.models['card'].findOne({
                where: {
                    tenantId,
                    billNo: {
                        [Op.like]: `PZ${ymd}%`
                    }
                },
                order: [['id', 'desc']]
            })
            if (!card) {
                return "PZ" + ymd + "-1";
            } else {
                let billNo = card.billNo.split('-')[1]
                return "PZ" + ymd + "-" + (tools.xe.toNumber(billNo) + 1);
            }
        }
        else {
            let no = await db.query(
                `select count(*) total from invoice where tenantId=${tenantId}
                and transType=${transType} and convert(varchar(10),createdAt,120)='${billDate}' ` , {type: QueryTypes.SELECT, plain: true})
            let num = 0
            if(no) {
                num = tools.xe.toNumber(no.total)
            }
            return  prefix + ymd + '-' + (num + 1);
        }
    } catch (e) {
        throw Error('票号生成失败')
    }
}
// 应付明细期初是否存在，不存在则插入
const saveMoneyInit = async (model) => {
    let type = moneyType(model)
    if(!type) return
    if (type === 'yf' || type === 'ys') {
        let detailMod = ''
        if(type === 'yf') detailMod = 'moneyYfDetail'
        if(type === 'ys') detailMod = 'moneyYsDetail'
        let hasQc = await db.models[detailMod].findOne({
            where: {
                buId: model.buId,
                tenantId: model.tenantId,
                transTypeName: '期初'
            }
        })
        // 写期初行
        if(!hasQc) {
            let hasInit = await db.models['initMoney'].findOne({
                where: {
                    buId: model.buId,
                    tenantId: model.tenantId
                }
            })
            let init = db.models[detailMod].build()
            init.billDate = '1970-01-01'
            init.transType = 0
            init.transTypeName = '期初'
            init.buId = model.buId
            init.tenantId = model.tenantId
            init.billId = 0
            init.amount = 0
            init.rpAmount = 0
            init.arrears = 0
            init.seq = 1
            init.ctime = tools.getTime()
            // 有期初应收付
            init.initM = hasInit ? ( type === 'ys' ? hasInit.ys : hasInit.yf) : 0
            init.leftM = hasInit ? (type === 'ys' ? hasInit.ys : hasInit.yf) : 0
            await init.save()
        }
    }
}
const moneyType = (model) => {
    if(['PUR', 'YFK', 'PAYMENT', 'YF'].indexOf(model.billType) !== -1 || model.otherType === '预付冲应付') return  'yf' // 应付
    if(['SALE', 'YSK', 'YSG', 'RECEIPT', 'YS'].indexOf(model.billType) !== -1 || model.otherType === '预收冲应收') return 'ys' // 应收
    return ''
}
// 是否可以审核
const billCanEdit = async (ym, tenantId) => {
    let zq = await tools.currentZq(tenantId);
    let currentYm = zq.ym
    if (tools.dayjs(ym).isBefore(currentYm)) {
        throw Error(`【${ym}】已结账，不能修改。`)
    }
}
// 审核
const toAccounted = async (ctx, ids) => {
    try {
        let tenantId = ctx.user.tenantId
        let uid = ctx.user.id
        // 查看id中的数据合法性
        let invoice = await db.models['invoice'].findOne({
            where: {
                tenantId,
                id: ids[0]
            }
        })

        if (invoice.billState !== 'draft') {
            return ctx.err('只能审核草稿数据')
        }
        if (['SALE', 'PUR', 'OO', 'OI'].indexOf(invoice.billType) !== -1) {
            // 检测库存 是否够
            await detectStock(invoice.id, 0)
        }

        await db.transaction(async () => {
            invoice.accountedBy = uid;
            invoice.accountedAt = tools.getTime()
            invoice.billState = 'accounted';
            await invoice.save()
            // 更新库存
            if (['PUR', 'SALE', 'OO', 'OI'].indexOf(invoice.billType) !== -1) {
                await updateInventory(tenantId, invoice.id,'cal')
                await hxYusf(invoice, 'accounted')
            }
            if (['RECEIPT', 'PAYMENT'].indexOf(invoice.billType) !== -1) {
                let sqls = `select billNo,transType,arrears,
       iif(transType in(150502,150602),-(isnull(cast(nowCheck as float),0)+isnull(yhAmount,0)),(isnull(nowCheck,0)+isnull(yhAmount,0))) as hxAmount 
                from v_main_withhx where tenantId=${invoice.tenantId} and id in(select billId from invoice_receipt where iid=${invoice.id}) `

                let moreReceipt = await db.query(sqls,{type: QueryTypes.SELECT})
                for (let i = 0; i < moreReceipt.length; i++) {
                    if(tools.xe.toNumber(moreReceipt[i].arrears) < tools.xe.toNumber(moreReceipt[i].hxAmount)) {
                        throw new Error(`${moreReceipt[i].billNo}核销总金额大于票据结余金额`)
                    }
                }
            }
            await createCard(invoice, tenantId, uid)
        })
        // 生成审核日志
        await tools.saveLogInvoice(tenantId, uid, invoice.id, "审核", invoice);
        return ctx.suc('审核成功')
    }
    catch (e) {
        throw new Error(e)
    }
}
// 核销 预收 预付款
const hxYusf = async (invoice, type) => {
    if(tools.xe.toNumber(invoice.transType) === 150501 || tools.xe.toNumber(invoice.transType) === 150601) {
        let list = await db.models['invoiceDikou'].findAll({
            where: {
                tenantId: invoice.tenantId,
                iid: invoice.id
            }
        })
        if(list.length > 0) {
            for (let i = 0; i < list.length; i++) {
                let hx = tools.xe.toNumber(list[i].hxAmount)
                let mo = await db.models['invoice'].findOne({
                    where: {
                        tenantId: invoice.tenantId,
                        id: list[i].relId
                    }
                })
                if(mo) {
                    if(mo.billState !== 'accounted') {
                        throw new Error('抵扣票据已退审')
                    }
                    // 审核业务单据 抵扣
                    if(type === 'accounted') {
                        let hxAmount = mo.hxAmount
                        mo.hxAmount = tools.xe.add(hxAmount, hx)
                        mo.leftAmount = tools.xe.subtract(mo.totalAmount, tools.xe.add(hxAmount, hx))
                        await mo.save()
                    }
                    if(type === 'waste') {
                        let hxAmount = mo.hxAmount
                        mo.hxAmount = tools.xe.subtract(hxAmount, hx)
                        mo.leftAmount = tools.xe.subtract(mo.totalAmount, tools.xe.subtract(hxAmount, hx))
                        await mo.save()
                    }
                }
            }
        }
    }
}

// 如果有预收 预付，保存预付预付核销单
const saveYsfList = async (invoice, ctx) => {
    if(invoice.transType!==150501 && invoice.transType!==150502) {
        return
    }
    if(tools.xe.toNumber(invoice.ysAmount) === 0){
        return
    }
    let list = await db.models['invoiceDikou'].findAll({
        where: {
            tenantId: invoice.tenantId,
            iid: invoice.id
        }
    })
    if(list.length === 0) return
    let hxbillIds =[]
    list.map(row => {
        hxbillIds.push(row.relId)
    })
    let sql = `select b.id, b.transTypeName,b.transType,b.tenantId,b.billType,b.billDate,b.billNo,b.totalAmount,
                      b.hxAmount,b.leftAmount,
                      a.hxAmount nowCheck from invoice_dikou as a inner join invoice b on a.relId=b.id and a.iid=${invoice.id} and
                                                                                          a.relId in(${hxbillIds.join(',')}) `
    let hxs = await db.query(sql, {type: QueryTypes.SELECT})
    if(hxs.length === 0) return
    if(list.length > 0 && hxs.length > 0) {
        let user = ctx.user
        let tenantId = user.tenantId;
        let buId = invoice.buId
        let doId = invoice.doId
        let billDate = invoice.billDate
        let cby = invoice.cby
        let amount = invoice.ysAmount
        let billType = 'YS2YS'
        let otherType = '预收冲应收'
        let transTypeName = '核销单'
        let transType = 153201 // 冲销
        let remark = invoice.billNo+'自动生成'
        if(invoice.billType === 'PUR') {
            billType = 'YF2YF'
            otherType = '预付冲应付'
        }
        let infos = []
        for (let i = 0; i < hxs.length; i++) {
            let inv = hxs[i]
            infos.push({
                listType: 'hxList',tenantId,iid: 0,billType,transType,billId:inv.id,srcBillType:inv.billType,
                srcTransType: inv.transType,srcBillNo: inv.billNo,srcTransTypeName: inv.transTypeName,
                billDate: inv.billDate,totalAmount:inv.totalAmount, arrears: inv.arrears,hxAmount:0,leftAmount: inv.leftAmount,
                nowCheck: inv.nowCheck,remark: invoice.billNo+'自动生成'
            })
        }
        infos.push({
            listType: 'billList',tenantId,iid: 0,billType,transType,billId:invoice.id,srcBillType:invoice.billType,
            srcTransType: invoice.transType,srcBillNo: invoice.billNo,srcTransTypeName: invoice.transTypeName,
            billDate: invoice.billDate,totalAmount:invoice.totalAmount,arrears: invoice.arrears,hxAmount:0,leftAmount: invoice.arrears,
            nowCheck: invoice.ysAmount,remark: invoice.billNo+'自动生成'
        })
        let createdAt = tools.getTime()
        let hasModel = await db.models['invoice'].findOne({
            where: {
                tenantId,
                transType: 153201,
                byIid: invoice.id
            }
        })
        let model = {
            billDate,
            tenantId,
            buId,
            transTypeName: transTypeName,
            otherType: otherType,
            transType: transType,
            billType: billType,
            billState: 'accounted',
            totalAmount: amount,
            amount: amount,
            arrears: amount,
            doId,
            cby,
            isAuto: 1,
            remark,
            byIid: invoice.id,
        }
        let res = await db.transaction(async () => {
            if(hasModel) {
                model.billNo = hasModel.billNo
                model.billState = 'accounted'
                model.updatedAt = createdAt
            }
            else {
                model.billNo = await setBillNo(tenantId, transType)
                model.createdAt = createdAt
            }
            if(hasModel) {
                await db.models['invoice'].update(model, {
                    where: {
                        tenantId,
                        id: hasModel.id
                    }
                })
                model.id = hasModel.id
            }
            else {
                let ret = await db.models['invoice'].create(model)
                model.id = ret.id
            }
            infos.map(row => {
                row.tenantId = tenantId
                row.iid = model.id
            })
            if(hasModel) {
                await db.models['invoiceReceipt'].destroy({
                    where: {
                        tenantId,
                        iid: hasModel.id
                    }
                })
            }
            await db.models['invoiceReceipt'].bulkCreate(infos)
            let hasYs = await db.models['invoiceInfo'].findAll({
                where: {
                    tenantId,iid: invoice.id
                }
            })
            let ys = hasYs.filter(row => {
                return !!row.ysId
            })
            if(ys.length > 0) {
                let sql = `
                    update a set a.hxQty=b.qty,a.hxAmount=b.amount from invoice_info_ys a
                                                                            inner join
                                                                        (
                                                                            SELECT a.tenantId,b.ysId,
                                                                                   sum(case when a.billState='accounted' then b.qty else 0 end) qty,
                                                                                   sum(case when a.billState='accounted' then isnull(b.amount,0) else 0 end) amount
                                                                            from invoice a inner join v_main_info b on a.id=b.iid and isnull(b.ysId,0)<>0
                                                                                and a.id=${invoice.id}
                                                                            GROUP BY a.tenantId,b.ysId
                                                                        ) b on a.tenantId=b.tenantId and a.id=b.ysId
                `
                await db.query(sql, {type: QueryTypes.UPDATE})
            }
            // 如果是预收商品，更新核销数量及金额
            return model
        })
        return ctx.suc('保存成功 ', res)
    }
}
// 检测是否有收款单据
const detectHasReceipt = async (tenantId, id) => {
    let has = await db.models['appSk'].count({
        where: {
            tenantId,
            billId: id
        }
    })
    if (has > 0) {
        throw Error('单据已存在于领单收款中,不能退审')
    }
    let hasRecSql = `select count(*) total from invoice a inner join invoice_receipt b on a.tenantId=b.tenantId and a.id=b.iid
        and a.tenantId=${tenantId} and b.billId=${id} and a.billState in('accounted', 'draft')
    `
    const hasRec = await db.query(hasRecSql, {type: QueryTypes.SELECT, plain: true})
    if (hasRec.total > 0) {
        throw Error('单据已存在于收款单中,不能退审')
    }
}
// 检测预收商品
const detectYsGoods = async (invoiceInfo) => {
    let ysId = invoiceInfo.ysId;
    let price = invoiceInfo.price ? tools.xe.toNumber(invoiceInfo.price) : 0
    let unit = invoiceInfo.unit
    let invoiceInfoYs = await db.models['invoiceInfoYs'].findOne({
        where: {
            id: ysId
        }
    })
    if (!invoiceInfoYs) throw Error('未找到相应预收商品项目')
    let price1 = invoiceInfoYs.price ? tools.xe.toNumber(invoiceInfoYs.price) : 0
    let unit1 = invoiceInfoYs.unit
    if (price1 !== price) throw Error("不允许更改预收商品价格");
    if (unit1 !== unit) throw Error("不允许更改预收商品单位");
}
// 保存业务票据
const saveInvoiceData = async (ctx) => {
    try {
        let invoice = ctx.request.body
        let user = ctx.user
        let uid = ctx.user.id
        let tenantId = user.tenantId
        let transType = tools.xe.toNumber(invoice.transType)
        let billType = invoice.billType
        let isAdd = true
        let transTypeName = invoice.transTypeName
        if (!invoice.billDate) return ctx.err('请选择开票日期');
        if (!transType || !billType || !transTypeName) return ctx.err('未知票据类型');
        let op = isAdd ? "新增" : "修改";
        let byCell = invoice.ter === 'cell' ? 1 : 0
        let billDate = invoice.billDate
        let bm = tools.dayjs(billDate).month()
        let cm = tools.dayjs(tools.getDay()).month()
        // if (Math.abs(bm - cm) > 2) {
        //     return ctx.err('禁止跨3个月录入数据')
        // }
        invoice.postData = JSON.stringify(invoice)
        if (['SALE', 'PUR', 'OO', 'OI'].indexOf(billType) !== -1) {
            await updateAssQty(ctx)
        }
        let invoiceModel = null
        if (invoice.billNo && !invoice.id) {
            return ctx.err('保存失败')
        }
        // 修改
        if (invoice.id) {
            isAdd = false
            // 票据是否属于当前用户
            invoiceModel = await db.models['invoice'].findOne({
                where: {
                    tenantId,
                    id: invoice.id
                }
            })
            if (!invoiceModel) return ctx.err('未找到票据或者已被删除');
            if (invoiceModel.isInit) return ctx.err("不能修改期初数据");
            if (invoiceModel.billState === 'del') return ctx.err("不能修改已删除数据");
            if (invoiceModel.billState === 'accounted') return ctx.err("不能修改已审核数据");
        }
        // 新增
        else {
            invoice.billNo = await setBillNo(tenantId, transType)
            invoice.byCell = byCell;
            // 检查权限
            invoice.createdAt = tools.getTime()
            invoice.cby = uid
        }
        if (!invoice.billNo) return ctx.err("没有票据号");
        let salesId = invoice.salesId ? invoice.salesId : 0
        let salesName = invoice.salesName ? invoice.salesName : 0
        if (!salesName) if (salesId) return ctx.err("请选择销售员");
        if (salesId) if (!salesName) return ctx.err("请选择销售员");
        let invoiceInfos = ctx.request.body.infos
        tools.setDefault(invoice, 'invoice')
        invoice.postData = JSON.stringify(invoice)

        // if (['SALE', 'PUR', 'OO', 'OI'].indexOf(billType) !== -1) invoiceInfos = ctx.request.body.invoiceInfos
        // if (['PAYMENT', 'RECEIPT'].indexOf(billType) !== -1) invoiceInfos = ctx.request.body.invoiceReceipts
        // if (['YSK', 'YFK', 'SR', 'ZC'].indexOf(billType) !== -1) invoiceInfos = ctx.request.body.invoiceOthers
        //
        if (['SALE', 'PUR', 'OO', 'OI', 'YSK', 'YFK', 'SR', 'ZC', 'ZZ'].indexOf(billType) !== -1) {
            if (!invoiceInfos || invoiceInfos.length === 0) return ctx.err("没有明细数据");
        }
        // 票据是否能编辑
        //         billCanEdit(invoice.getBillDate(), tenantId);
        invoice.billState = 'draft'
        invoice.tenantId = tenantId
        let billAt = invoice.billDate
        invoice.updatedAt = tools.getTime()
        let deliverIds = invoice.deliverIds ? (invoice.deliverIds === '[]' ? "" : invoice.deliverIds) : ""
        let deliverNames = invoice.deliverNames ? invoice.deliverNames : ''
        if (deliverIds) {
            if (deliverIds === '0') deliverIds = "";
            if (deliverIds.indexOf("0,") === 0) {
                deliverIds = deliverIds.substring(2);
            }
            if (deliverIds.indexOf("NaN,") === 0) {
                deliverIds = deliverIds.substring(4);
            }
        }
        let accId = tools.xe.toNumber(invoice.accId)
        let accId1 = tools.xe.toNumber(invoice.accId1)
        let buId = tools.xe.toNumber(invoice.buId)
        let doBy = tools.xe.toNumber(invoice.doId)
        let yhAmount = 0; // 收付款优惠总金额
        let calAmount = 0;
        let qtys = 0;
        let totalDiscount = 0;
        let totalAmount = tools.xe.toNumber(invoice.totalAmount) // 总金额
        let ysAmount = tools.xe.toNumber(invoice.ysAmount) // 预收/预付
        let disAmount = tools.xe.toNumber(invoice.disAmount) // 票据优惠
        let rpAmount = tools.xe.toNumber(invoice.rpAmount) // 收/付款金额
        let accAmount = tools.xe.toNumber(invoice.accAmount) // 账户1金额
        let accAmount1 = tools.xe.toNumber(invoice.accAmount1) // 账户2金额
        invoice.batchReceiptId = 0
        invoice.accId = accId
        invoice.accId1 = accId1
        invoice.accAmount = accAmount;
        invoice.accAmount1 = accAmount1;
        invoice.ysAmount = ysAmount;
        invoice.billYear = billAt.substring(0, 4)
        invoice.billMonth = billAt.substring(5, 7);
        invoice.buId = buId;
        invoice.doId = doBy;
        invoice.deliverIds = deliverIds;
        invoice.deliverNames = deliverNames;
        invoice.salesId = salesId;
        switch (transType) {
            case 150501:
            case 150502:
            case 150601:
            case 150602:
            case 150603:
            case 150706:
            case 150806: {
                if (invoice.accId) {
                    if (!rpAmount) return ctx.err('请输入账户金额');
                }
                if (rpAmount) {
                    if (!accId) return ctx.err("请选择账户");
                    if (rpAmount) {
                        let s = "本次收/付款 大于 应收/付金额";
                        if (totalAmount > 0)
                            if (rpAmount > tools.minus(totalAmount, disAmount)) {
                                return ctx.err(s);
                            }
                    }
                }
                for (let i = 0; i < invoiceInfos.length; i++) {
                    let invoiceInfo = invoiceInfos[i]
                    tools.setDefault(invoiceInfo, 'invoiceInfo')
                    if (!invoiceInfo.invId) continue;
                    invoiceInfo.tenantId = tenantId;
                    let subAmount = tools.xe.toNumber(invoiceInfo.amount)
                    let price = tools.xe.toNumber(invoiceInfo.price)
                    let qty = tools.xe.toNumber(invoiceInfo.qty)
                    if (qty === 0) return ctx.err("数量不能等于 0 ");
                    let p = tool.xe.round((tool.xe.add(tool.xe.divide(subAmount,qty), deduction)),2)
                    if(tool.xe.round(price, 2) !== p)
                        throw Error(invoiceInfo.invName + "  金额不等于 数量 * 单价");


                    totalDiscount = tools.add(totalDiscount, tools.multiply(qty, invoiceInfo.deduction))
                    let calNum = tools.xe.toNumber(invoiceInfo.calNum)
                    let detail = tools.multiply(invoiceInfo.qty, calNum)
                    // 最小单位不能有小数
                    if (tools.xe.isFloat(detail)) return ctx.err(invoiceInfo.invName + "  最小单位数量不能为小数");
                    let sub = tools.xe.toNumber(invoiceInfo.amount)
                    switch (transType) {
                        case 150601:
                        case 150602:
                        case 150603:
                        case 150706:
                        case 150806:
                        case 150502:
                        case 150501: {
                            calAmount = tools.add(calAmount, sub)
                        }
                            break;
                    }
                }
                invoice.accAmount = rpAmount;
            }
                break;
            case 153001:
            case 153101: {
                let os = transType === 153001 ? "收款" : "付款";
                if (buId === 0) return ctx.err("请选择客户");
                if (accId === 0) return ctx.err("请选择" + os + "账户");
                //                if (invoice.getInvoiceReceipts().size() == 0) return Ret.err("没有明细");
                if (accId === accId1) return ctx.err("账号2与账号1不能相同");
                if (accId1) {
                    if (!accAmount1) return ctx.err("请输入" + os + "金额1");
                }
                if (accAmount1 !== 0) {
                    if (!accId1) {
                        return ctx.err("请选择" + os + "账户1");
                    }
                }
                if (invoiceInfos.length > 0) {
                    for (let i = 0; i < invoiceInfos.length; i++) {
                        let receiptInfo = invoiceInfos[i]
                        tools.setDefault(receiptInfo, 'invoiceReceipt')
                        let nowCheck = tools.xe.toNumber(receiptInfo.nowCheck)
                        let yh = tools.xe.toNumber(receiptInfo.yhAmount)
                        if (!nowCheck) return ctx.err("请输入本次" + os + "金额")
                        yhAmount = tools.add(yhAmount, yh)
                        calAmount = tools.add(calAmount, nowCheck, yh)
                        disAmount = tools.add(disAmount, yh)
                    }
                    totalAmount = calAmount;
                    invoice.totalAmount = calAmount;
                    rpAmount = calAmount;
                } else {
                    calAmount = tools.add(accAmount, accAmount1);
                    totalAmount = calAmount
                    invoice.totalAmount = totalAmount;
                    rpAmount = totalAmount;
                }

            }
                break
            case 153401:
            case 153402: {
                let srAmount = 0;
                for (let i = 0; i < invoiceInfos.length; i++) {
                    let otherInfo = invoiceInfos[i]
                    tools.setDefault(otherInfo, 'invoiceOther')
                    srAmount = tools.add(srAmount, otherInfo.amount)
                }
                calAmount = srAmount;
                totalAmount = srAmount;
                invoice.totalAmount = srAmount;
                rpAmount = srAmount;
            }
                break;
            // 应收/付
            case 153404:
            case 153405: {

            }
                break;
            // 预收 商品
            case 153403: {
                if (totalAmount === 0) return ctx.err("请输入预收金额");
                invoice.accAmount = rpAmount
                invoice.leftAmount = rpAmount
                //
                for (let i = 0; i < invoiceInfos.length; i++) {
                    let invoiceInfoYs = invoiceInfos[i]
                    tools.setDefault(invoiceInfoYs, 'invoiceInfoYs')
                    if (!invoiceInfoYs.invId) continue
                    invoiceInfoYs.tenantId = tenantId
                    let subAmount = tools.xe.toNumber(invoiceInfoYs.amount)
                    let price = tools.xe.toNumber(invoiceInfoYs.price)
                    let qty = tools.xe.toNumber(invoiceInfoYs.qty)
                    if (qty < 0) return ctx.err('数量小于 0 ')
                    // 算单价
                    if (billType === 'YSG') {
                        let cp1 = tools.xe.round(tools.multiply(price, qty), 2)
                        if (cp1 !== subAmount) {
                            return ctx.err(invoiceInfoYs.invName + "  金额不等于 数量 * 单价");
                        }
                    }
                    let calNum = tools.xe.toNumber(invoiceInfoYs.calNum)
                    let detail = tools.multiply(invoiceInfoYs.qty, calNum)
                    // 最小单位不能有小数
                    if (detail.toString().indexOf('.') !== -1) {
                        return ctx.err(invoiceInfoYs.invName + "  最小单位数量不能为小数");
                    }
                    let sub = tools.xe.toNumber(invoiceInfoYs.amount)
                    calAmount = tools.add(calAmount, sub)
                    qtys = tools.add(qtys, qty);
                }
                rpAmount = calAmount
            } break;
            case 153406:
            case 153407: {
                let category = null
                if (transType === 153407) {
                    category = await getSubjectByName("预收账款", tenantId);
                    if (!category) return ctx.err("预收账款科目设置错误");
                }
                if (transType === 153406) {
                    category = await getSubjectByName("预付账款", tenantId);
                    if (!category) return ctx.err("预付账款科目设置错误");
                }

                let srAmount = 0
                for (let i = 0; i < invoiceInfos.length; i++) {
                    let otherInfo = invoiceInfos[i]
                    tools.setDefault(otherInfo, 'invoiceOther')
                    srAmount = tools.add(srAmount, otherInfo.amount)
                }
                calAmount = srAmount;
                for (let i = 0; i < invoiceInfos.length; i++) {
                    let otherInfo = invoiceInfos[i]
                    tools.setDefault(otherInfo, 'invoiceOther')
                    if (transType === 153407 || transType === 153406) {
                        otherInfo.subjectId = category.id
                        otherInfo.subjectName = category.name
                    }
                }
                invoice.rpAmount = srAmount;
                invoice.totalAmount = srAmount;
                invoice.leftAmount = srAmount;
                rpAmount = srAmount;
                rpAmount=0
                totalAmount = srAmount;
            }
                break;
            case 160001: {

            }
                break;
        }
        if(invoice.transType !== 153406 && invoice.transType !== 153407) {
            if (totalAmount !== calAmount) return ctx.err("明细合计不等于总金额");
        }
        let arrears = tools.minus(calAmount, rpAmount, disAmount, ysAmount); // 本次欠款
        //
        invoice.yhAmount = yhAmount;
        if(invoice.transType !== 153406 && invoice.transType !== 153407) {
            invoice.totalAmount = calAmount;
        }
        invoice.disAmount = disAmount;
        invoice.rpAmount = rpAmount;
        invoice.arrears = arrears;
        if(invoice.transType!==153403) {
            invoice.leftAmount = arrears;
        }
        invoice.amount = tools.minus(calAmount, disAmount, ysAmount)
        invoice.qty = qtys
        invoice.totalDiscount = totalDiscount;
        //
        let quickSearch = []
        invoice.cbyName && quickSearch.push(invoice.cbyName)
        invoice.billDate && quickSearch.push(invoice.billDate)
        invoice.billNo && quickSearch.push(invoice.billNo)
        invoice.buName && quickSearch.push(invoice.buName)
        invoice.remark && quickSearch.push(invoice.remark)
        invoice.salesName && quickSearch.push(invoice.salesName)
        invoice.doName && quickSearch.push(invoice.doName)
        invoice.totalAmount && quickSearch.push(invoice.totalAmount)
        invoice.arrears && quickSearch.push(invoice.arrears)
        for (let i = 0; i < invoiceInfos.length; i++) {
            delete invoiceInfos[i].id
            if (typeof invoiceInfos[i].invName !== 'undefined') {
                invoiceInfos[i].invName && quickSearch.push(invoiceInfos[i].invName)
            }
            if (typeof invoiceInfos[i].srcBillNo !== 'undefined') {
                invoiceInfos[i].srcBillNo && quickSearch.push(invoiceInfos[i].srcBillNo)
            }
            if (typeof invoiceInfos[i].nowCheck !== 'undefined') {
                invoiceInfos[i].nowCheck && quickSearch.push(invoiceInfos[i].nowCheck)
            }
            invoiceInfos[i].remark && quickSearch.push(invoiceInfos[i].remark)
        }
        invoice.quickSearch = quickSearch.join(',').substring(0, 2999)
        let ysam = 0
        if (invoice.dikouList && invoice.dikouList.length > 0) {
            invoice.dikouList.map(row => {
                ysam = tools.add(ysam, row.hxAmount)
            })
            if (ysam !== tools.xe.toNumber(invoice.ysAmount)) {
                return ctx.err('抵扣金额不等于选择票据核销金额之和')
            }
        }
        // 保存主表
        let ret = await db.transaction(async () => {
            let insertModel = {
                tenantId: invoice.tenantId,
                billState: invoice.billState,
                billNo: invoice.billNo,
                billDate: invoice.billDate,
                billYear: invoice.billYear,
                billMonth: invoice.billMonth,
                billType: invoice.billType,
                transType: invoice.transType,
                transTypeName: invoice.transTypeName,
                otherType: invoice.otherType,
                buId: invoice.buId,
                accId: invoice.accId,
                accAmount: invoice.accAmount,
                accId1: invoice.accId1,
                accAmount1: invoice.accAmount1,
                sendManId: invoice.sendManId,
                salesId: invoice.salesId,
                doId: invoice.doId,
                employeeId: invoice.employeeId,
                accountedBy: invoice.accountedBy,
                sendDate: invoice.sendDate,
                lastPayTime: invoice.lastPayTime,
                totalAmount: invoice.totalAmount,
                totalDiscount: invoice.totalDiscount,
                disAmount: invoice.disAmount,
                ysAmount: invoice.ysAmount,
                amount: invoice.amount,
                rpAmount: invoice.rpAmount,
                arrears: invoice.arrears,
                hxAmount: invoice.hxAmount,
                yhAmount: invoice.yhAmount,
                leftAmount: invoice.leftAmount,
                qty: invoice.qty,
                isYs: invoice.isYs,
                isYz: invoice.isYz,
                isFt: invoice.isFt,
                isGz: invoice.isGz,
                remark: invoice.remark,
                subRemark: invoice.subRemark,
                isHc: invoice.isHc,
                isAuto: invoice.isAuto,
                printNo: invoice.printNo,
                byIid: invoice.byIid,
                files: invoice.files,
                wastedBy: invoice.wastedBy,
                updatedId: invoice.updatedId,
                otherTypeId: invoice.otherTypeId,
                postData: invoice.postData,
                isLoad: invoice.isLoad,
                deliverIds: invoice.deliverIds,
                deliverNames: invoice.deliverNames,
                byCell: invoice.byCell,
                isDelete: invoice.isDelete,
                accountedAt: invoice.accountedAt,
                deletedBy: invoice.deletedBy,
                wastedAt: invoice.wastedAt,
                deletedAt: invoice.deletedAt,
                isInit: invoice.isInit,
                batchReceiptId: invoice.batchReceiptId,
                byScan: invoice.byScan,
                toYs: invoice.toYs,
                quickSearch: invoice.quickSearch
            }
            if (isAdd) {
                insertModel.cby = uid
                insertModel.createdAt = tools.getTime()
                let model = await db.models['invoice'].create(insertModel)
                insertModel.id = model.id
            }
            else {
                insertModel.cby = uid
                insertModel.updatedAt = tools.getTime()
                await invoiceModel.update(insertModel)
                insertModel.id = invoice.id
                if (invoice.transType === 150501 || invoice.transType === 150601) {
                    // 预收金额为0，抵扣列表
                    if(tools.xe.toNumber(invoice.ysAmount) === 0) {
                        await db.models['invoiceDikou'].destroy({
                            where: {
                                tenantId: insertModel.tenantId,
                                iid: insertModel.id
                            }
                        })
                    } else {
                        if (invoice.dikouList && invoice.dikouList.length > 0) {
                            await db.models['invoiceDikou'].destroy({
                                where: {
                                    tenantId: insertModel.tenantId,
                                    iid: insertModel.id
                                }
                            })
                        }
                    }
                }
            }
            if (invoice.dikouList) {
                if (invoice.transType === 150501 || invoice.transType === 150601) {
                    if (invoice.dikouList.length > 0) {
                        let dikou = []
                        invoice.dikouList.map(row => {
                            ysam = tools.add(ysam, row.hxAmount)
                            dikou.push({
                                iid: insertModel.id,
                                tenantId: insertModel.tenantId,
                                relId: row.id,
                                hxAmount: row.hxAmount
                            })
                        })
                        await db.models['invoiceDikou'].bulkCreate(dikou)
                    }
                }
            }
            switch (transType) {
                case 150501:
                case 150502:
                case 150601:
                case 150602:
                case 150603:
                case 150706:
                case 150806: {
                    if (!isAdd) {
                        await db.models['invoiceInfo'].destroy({
                            where: {
                                iid: insertModel.id,
                                tenantId
                            }
                        },)
                    }
                    for (let i = 0; i < invoiceInfos.length; i++) {
                        invoiceInfos[i].iid = insertModel.id
                        invoiceInfos[i].tenantId = tenantId
                    }
                    await db.models['invoiceInfo'].bulkCreate(invoiceInfos,)
                }
                    break;
                case 153001: // 收款
                case 153101: { // 付款
                    if (!isAdd) {
                        await db.models['invoiceReceipt'].destroy({
                            where: {
                                tenantId,
                                iid: insertModel.id
                            }
                        })
                    }
                    for (let i = 0; i < invoiceInfos.length; i++) {
                        delete invoiceInfos[i].id
                        invoiceInfos[i].iid = insertModel.id
                        invoiceInfos[i].tenantId = insertModel.tenantId
                    }
                    if (invoiceInfos.length > 0) // 收付款可以不对应明细
                        await db.models['invoiceReceipt'].bulkCreate(invoiceInfos)
                } break
                case 153403: {
                    if (!isAdd) {
                        await db.models['invoiceInfoYs'].destroy({
                            where: {
                                iid: insertModel.id
                            }
                        })
                    }
                    for (let i = 0; i < invoiceInfos.length; i++) {
                        invoiceInfos[i].iid = insertModel.id
                        invoiceInfos[i].tenantId = insertModel.tenantId
                    }
                    await db.models['invoiceInfoYs'].bulkCreate(invoiceInfos,)
                }
                    break
                case 153401:
                case 153402:
                case 153406:
                case 153407: {
                    if (!isAdd) {
                        await db.models['invoiceOther'].destroy({
                            where: {
                                tenantId,
                                iid: insertModel.id
                            }
                        })
                    }
                    for (let i = 0; i < invoiceInfos.length; i++) {
                        invoiceInfos[i].iid = insertModel.id
                        invoiceInfos[i].tenantId = insertModel.tenantId
                    }
                    await db.models['invoiceOther'].bulkCreate(invoiceInfos,)
                } break
                case 153404:
                case 153405: {

                } break
                case 160001: {

                } break
            }
            return insertModel
        })
        // saveHistPrice(ret, invoiceInfos)
        // saveContactSales(ret);
        // tools.saveLogInvoice(tenantId, uid, ret.id, op, invoice);
        return ctx.suc("保存成功", ret);
    }
    catch (e) {
        return ctx.err(e)
    }
}
// 更新最后一次销售、采购单价
const saveHistPrice = async (insertModel, infos) => {
    if(insertModel.billType === 'PUR' || insertModel.billType === 'SALE') {
        let sql = `
            with bills as (
                select a.tenantId,a.buId,a.transType,b.invId,b.unitId,b.price,b.deduction,b.iid from invoice a inner join
                  v_main_info b on a.tenantId=b.tenantId and a.id=b.iid and a.id=${insertModel.id}
                   and b.id in (
                     select max(b.id) id
                             from invoice a inner join v_main_info b on a.tenantId=b.tenantId and a.id=b.iid and a.id=${insertModel.id}
                            where isnull(b.price,0)<>0 group by a.buId, b.invId,b.unit
                      )
            )
            merge into price_his a using bills b on a.tenantId=b.tenantId and a.buId=b.buId and a.transType=b.transType and a.invId=b.invId and a.unitId=b.unitId
            when matched then update set a.price=b.price,a.deduction=b.deduction
            when not matched then insert (tenantId,buId,transType,invId,unitId,price,deduction)
            values (b.tenantId,b.buId,b.transType,b.invId,b.unitId,b.price,b.deduction);
        `;
        await db.query(sql, {type: QueryTypes.UPDATE})
    }
}
// 保存终端与业务员关系
const saveContactSales = async (invoice) => {
    if (invoice.billType === 'SALE') {
        if (invoice.buId && invoice.salesId) {
            let sql = `
                with bills as (select tenantId, buId, salesId
                               from invoice
                               where tenantId = ${invoice.tenantId} and id = ${invoice.id} and isnull(salesId, 0) <> 0
                ) merge into contact_sales a using bills b on 
                a.tenantId=b.tenantId and a.buId=b.buId and a.salesId=b.salesId 
                when not matched then insert (tenantId,buId,salesId) values (b.tenantId,b.buId,b.salesId);
            `
            await db.query(sql, {type: QueryTypes.UPDATE})
        }
    }
}
const saveContactGoods = async (invoice) => {
    await db.query(`exec updateContactGoodsTimes @tenantId=${invoice.tenantId},@transType=${invoice.transType},@buId=${invoice.buId},@iid=${invoice.id}`, {type: QueryTypes.UPDATE})
}

const getSubjectById = async (sid) => {
    return await db.models['category'].findByPk(sid)

}
const getSubjectByName = async (name, tenantId) => {
    return await db.models['category'].findOne({
        where: {
            tenantId,
            typeNumber: 'subject',
            name,
        }
    })
}
const isJdEqual = (list) => {
    let price1 = 0
    let price2 = 0
    for (let i = 0; i < list.length; i++) {
        let cardInfo = list[i]
        price1 = tools.xe.add(price1, cardInfo.price1)
        price2 = tools.xe.add(price2, cardInfo.price2)
    }
    if (price1 !== price2) throw Error("借贷不相等");
}
const saveLogCard =async  (tenantId, uid, id, op, data) => {
    try {
        let cardLog = {
            tenantId,
            op,
            cardId: id,
            uid,
            data: JSON.stringify(data)
        }
        await db.models['cardLog'].create(cardLog)
    }
    catch (e)
    {
        throw new Error(e)
    }

}
// 生成凭证
const createCard = async (invoiceModel, tenantId, uid) =>{
    let invoice = tools.xe.clone(invoiceModel, true)
    if(invoice.transType === 150502 || invoice.transType === 150602) {
        invoice.totalAmount = -tools.xe.toNumber(invoice.totalAmount, 0)
        invoice.disAmount = -tools.xe.toNumber(invoice.disAmount, 0)
        invoice.amount = -tools.xe.toNumber(invoice.amount, 0)
        invoice.rpAmount = -tools.xe.toNumber(invoice.rpAmount, 0)
        invoice.arrears = -tools.xe.toNumber(invoice.arrears, 0)
    }
    let billType = invoice.billType

    let transType = tools.xe.toNumber(invoice.transType)
    if (billType === 'OO') return; // 其它出库不生成凭证，结账时生成一张结转凭证
    let ct = tools.getTime()
    // 检测票据是否存在
    let card = await db.models['card'].findOne({
        where: {
            tenantId,
            byIid: invoice.id,
        }
    })
    if (card) {
        if (card.billState === 'accounted') {
            throw Error('票据已审核,不能重复审核。')
        }
        await db.models['cardInfo'].destroy({
            where: {
                tenantId,
                byIid: invoice.id,
            }
        })
    }
    else {
        card = db.models['card'].build()
        card.tenantId = tenantId
        card.billNo = await setBillNo(tenantId, 190001)
        card.createdAt = ct
        card.updatedAt = ct
        card.cby = uid
    }

    // 预收 商品，金额为0 时不审核
    if (billType === 'YSG') {
        if (tools.xe.toNumber(invoice.totalAmount) === 0) return
    }
    let contact = null
    if(invoiceModel.transType !== 160001) {
        if(!invoice.buId) throw Error('未找到往来单位')
        contact = await db.models['contact'].findOne({
            where: {
                id: invoice.buId
            }
        })
        if (!contact) throw Error('未找到往来单位')
    }


    let billAt = invoice.billDate
    card.billState = 'accounted'
    card.billDate = billAt
    card.buId = contact?contact.id:0
    card.isAuto = 1
    card.byIid = invoice.id
    card.accountedBy = uid
    card.accountedAt = ct
    let list = []
    // 设置主表摘要
    card.remark = `票号【${invoice.billNo}】生成`
    switch (transType) {
        case 150501:
        case 150502:
        case 150601:
        case 150602:
        case 150603: {
            let amount = tools.xe.toNumber(invoice.amount)
            let rpAmount = tools.xe.toNumber(invoice.rpAmount)
            let disAmount = tools.xe.toNumber(invoice.disAmount) // 销售优惠
            let ysAmount = tools.xe.toNumber(invoice.ysAmount) // 有预/付收款
            let totalAmount = tools.xe.toNumber(invoice.totalAmount) // 总金额
            let arrears = tools.xe.toNumber(invoice.arrears) // 欠款
            // 金额为0 ，不审核
            if (totalAmount === 0) return;
            //
            let category = {}
            if (rpAmount !== 0) {
                if (!invoice.accId) throw Error('请选择账号科目')
                category = await getSubjectById(invoice.accId);
                if (!category) throw Error('未知账户科目')
            }
            switch (transType) {
                case 150501:
                case 150502: {
                    // 1、借库存商品 2、借应付账款 （单据上有收款）3、贷银行存款 （单据上有收款）4、贷 应付账款（如果 单据上有付款）
                    let kcsp = await getSubjectByName("库存商品", tenantId);
                    if (!kcsp) throw Error("科目库存商品未设置");
                    // 1、借库存商品
                    if (totalAmount !== 0) {
                        let cardInfo = {
                            subjectId: kcsp.id,
                            price1: totalAmount,
                            // price1: transType === 150501 ? totalAmount : -totalAmount,
                            price2: 0,
                            remark: card.remark
                        }
                        list.push(cardInfo);
                    }
                    let yfzk = await getSubjectByName("应付账款", tenantId);
                    // 贷预付账款
                    if (ysAmount !== 0) {
                        let yszk = await getSubjectByName("预付账款", tenantId);
                        let cardInfos = {
                            subjectId: yszk.id,
                            price1: 0,
                            price2: ysAmount,
                            remark: card.remark
                        }
                        list.push(cardInfos);
                    }
                    // 如果单据上有付款
                    if (rpAmount !== 0) {
                        // 2、贷银行存款 （单据上有收款)
                        let cardInfo2 = {
                            subjectId: category.id,
                            price1: 0,
                            // price2: transType === 150501 ?rpAmount: -rpAmount
                            price2: rpAmount,
                            remark: card.remark
                        }
                        list.push(cardInfo2);
                    }
                    // 4、贷 应付账款（如果 单据上有付款）
                    if (arrears !== 0) {
                        let cardInfo1 = {
                            subjectId: yfzk.id,
                            price1: 0,
                            // price2: transType === 150501 ?arrears: -arrears
                            price2: arrears,
                            remark: card.remark
                        }
                        list.push(cardInfo1);
                    }
                }
                    break;
                case 150601:
                case 150602:
                case 150603: {
                    let ys = tools.minus(totalAmount, disAmount, ysAmount, rpAmount)
                    // 1、借应收账款 2、借银行存款 （单据上有收款）3、贷应收账款 （单据上有收款）4、贷 主营业务收入
                    //  1、借应收账款
                    let zyywsr = await getSubjectByName("主营业务收入", tenantId);
                    // 1、借应收账款
                    if (ys !== 0) {
                        let yszk = await getSubjectByName("应收账款", tenantId);
                        let cardInfo1 = {
                            subjectId: yszk.id,
                            price1: arrears,
                            // price1: transType === 150602 ? -arrears : arrears,
                            price2: 0,
                            remark: card.remark
                        }
                        list.push(cardInfo1);
                    }
                    //  借银行存款
                    if (rpAmount !== 0) {
                        // 2、借银行存款 （单据上有收款）
                        let cardInfo = {
                            subjectId: category.id,
                            // price1: transType === 150602 ? -rpAmount : rpAmount,
                            price1: rpAmount,
                            price2: 0,
                            remark: card.remark
                        }
                        list.push(cardInfo);
                    }
                    // 有优惠金额 借票据优惠
                    if (disAmount !== 0) {
                        let xsyh = await getSubjectByName("销售优惠", tenantId);
                        let cardInfo = {
                            subjectId: xsyh.id,
                            price1: disAmount,
                            // price1: transType === 150602 ? -disAmount : disAmount,
                            price2: 0,
                            remark: card.remark
                        }
                        list.push(cardInfo);
                    }
                    // 有预收款抵扣
                    if (ysAmount !== 0) {
                        let yszk = await getSubjectByName("预收账款", tenantId);
                        let cardInfo = {
                            subjectId: yszk.id,
                            price1: ysAmount,
                            price2: 0,
                            remark: card.remark
                        }
                        list.push(cardInfo);
                    }
                    // 3、贷 主营业务收入
                    if (totalAmount !== 0) {
                        let zysr = {
                            subjectId: zyywsr.id,
                            price1: 0,
                            price2: totalAmount,
                            // price2: transType === 150602 ? -totalAmount : totalAmount,
                            remark: card.remark
                        }
                        list.push(zysr);
                    }
                    break;
                }
            }
        }
            break;
        case 150706: //其他入库
        case 150806: {
            let totalAmount = tools.xe.toNumber(invoice.totalAmount); // 总金额
            // 金额为0 ，不审核
            if (totalAmount === 0) return;

            let subjectId = 0
            if(transType === 150706) {
                // 商品报溢收入 605103
                let sub = await db.models['category'].findOne({
                    where: {
                        tenantId,
                        code: '605103'
                    }
                })
                if(!sub) throw Error('未找到其他入库科目')
                subjectId = sub.id
            }
            if(transType === 150806) {
                if(invoice.otherType === '盘亏') {
                    // 其他出库费用 640202
                    let sub = await db.models['category'].findOne({
                        where: {
                            tenantId,
                            code: '640202'
                        }
                    })
                    if(!sub) throw Error('未找到其他出库科目')
                    subjectId = sub.id
                }
                if(invoice.otherType === '报损') {
                    // 商品报损支出 640201
                    let sub = await db.models['category'].findOne({
                        where: {
                            tenantId,
                            code: '640201'
                        }
                    })
                    if(!sub) throw Error('未找到其他出库科目')
                    subjectId = sub.id
                }
            }



            let kcsp = await getSubjectByName("库存商品", tenantId);
            if (!kcsp) throw Error("科目库存商品未设置");
            // 借库存商品  贷款 。。
            if (transType === 150706) {
                let cardInfo = {
                    subjectId: kcsp.id,
                    price1: totalAmount,
                    price2: 0,
                    remark: card.remark
                }
                list.push(cardInfo);
                let cardInfo1 = {
                    subjectId: subjectId,
                    price1: 0,
                    price2: totalAmount,
                    remark: card.remark
                }
                list.push(cardInfo1);
            }
            if (transType === 150806) {
                let cardInfo1 = {
                    subjectId: subjectId,
                    price1: totalAmount,
                    price2: 0,
                    remark: card.remark
                }
                list.push(cardInfo1);
                let cardInfo = {
                    subjectId: kcsp.id,
                    price1: 0,
                    price2: totalAmount,
                    remark: card.remark
                }
                list.push(cardInfo);
            }

        } break;
        case 153001: // 收/付款
        case 153101: {
            let category = {}
            let yhAmount = tools.xe.toNumber(invoice.yhAmount)
            let accTotal = tools.xe.add(invoice.accAmount, invoice.accAmount1)
            // 贷 应收账款
            let ys = tools.add(accTotal, yhAmount)
            let invoiceReceipts = await db.models['invoiceReceipt'].findAll({
                where: {
                    tenantId,
                    iid: invoice.id
                }
            })

            if (invoiceReceipts.length > 0) {
                let hx = 0;
                for (let i = 0; i < invoiceReceipts.length; i++) {
                    let invoiceReceipt = invoiceReceipts[i]
                    let nc = tools.xe.toNumber(invoiceReceipt.nowCheck)
                    let yc = tools.xe.toNumber(invoiceReceipt.yhAmount)
                    let sub = tools.add(nc, yc)
                    hx = tools.add(hx, sub)
                }
                if (ys !== hx) throw Error("合计金额错误");
            }
            // 保存凭证主表
            if (transType === 153001) {
                // 借银行账户1
                if(invoice.accId && invoice.accAmount) {
                    let cardInfo2 = {
                        subjectId: invoice.accId,
                        price1: invoice.accAmount,
                        price2: 0,
                        remark: card.remark
                    }
                    list.push(cardInfo2);
                }
                if(invoice.accId1 && invoice.accAmount1) {
                    let cardInfo2 = {
                        subjectId: invoice.accId1,
                        price1: invoice.accAmount1,
                        price2: 0,
                        remark: card.remark
                    }
                    list.push(cardInfo2);
                }

                // 如果 有收付款优惠,借收款优惠
                if (yhAmount !== 0) {
                    // 票据上有付款金额与账户
                    category = await getSubjectByName("收款优惠", tenantId);
                    if (!category) throw Error("收款优惠科目设置错误");
                    let cardInfo2 = {
                        subjectId: category.id,
                        price1: yhAmount,
                        price2: 0,
                        remark: card.remark
                    }
                    list.push(cardInfo2);
                }
                // 贷 应收账款
                if (ys !== 0) {
                    category = await getSubjectByName("应收账款", tenantId);
                    if (!category) throw Error("应收账款科目设置错误");
                    let cardInfo = {
                        subjectId: category.id,
                        price1: 0,
                        price2: ys,
                        remark: card.remark
                    }
                    list.push(cardInfo);
                }
            }
            if (transType === 153101) {
                // 借 应付账款
                category = await getSubjectByName("应付账款", tenantId);
                if (!category) throw Error("应付账款科目设置错误");
                if (ys !== 0) {
                    let cardInfo = {
                        subjectId: category.id,
                        price1: ys,
                        price2: 0,
                        remark: card.remark
                    }
                    list.push(cardInfo);
                }
                if(invoice.accId && invoice.accAmount) {
                    let cardInfo2 = {
                        subjectId: invoice.accId,
                        price1: 0,
                        price2: invoice.accAmount,
                        remark: card.remark
                    }
                    list.push(cardInfo2);
                }
                if(invoice.accId1 && invoice.accAmount1) {
                    let cardInfo2 = {
                        subjectId: invoice.accId1,
                        price1: 0,
                        price2: invoice.accAmount1,
                        remark: card.remark
                    }
                    list.push(cardInfo2);
                }

                // 如果 贷付款优惠
                if (yhAmount !== 0) {
                    // 票据上有付款金额与账户
                    category = await getSubjectByName("营业外收入", tenantId);
                    if (!category) throw Error("营业外收入科目错误");
                    let cardInfo2 = {
                        subjectId: category.id,
                        price1: 0,
                        price2: yhAmount,
                        remark: card.remark
                    }
                    list.push(cardInfo2);
                }
            }
        }
            break;
        case 153401: {
            // 其他收入
            let invoiceOthers = await db.models['invoiceOther'].findAll({
                where: {
                    iid: invoice.id
                }
            })
            // 借
            let sub1 = 0
            for (let j = 0; j < invoiceOthers.length; j++) {
                let otherInfo = invoiceOthers[j]
                let cardInfo = {
                    subjectId: otherInfo.accId,
                    price1: otherInfo.amount,
                    price2: 0,
                }
                if (j === 0) {
                    cardInfo.remark = invoice.billNo + "生成," + (otherInfo.remark ? otherInfo.remark : '')
                }
                list.push(cardInfo);
                sub1 = tools.add(sub1, otherInfo.amount)
            }
            // 贷
            for (let j = 0; j < invoiceOthers.length; j++) {
                let otherInfo = invoiceOthers[j]
                let cardInfo = {
                    subjectId: otherInfo.subjectId,
                    price1: 0,
                    price2: otherInfo.amount,
                }
                list.push(cardInfo);
            }
        }
            break;
        case 153402: {
            // 其他民支出
            // 借
            let sub1 = 0
            let invoiceOthers = await db.models['invoiceOther'].findAll({
                where: {
                    iid: invoice.id
                }
            })
            for (let j = 0; j < invoiceOthers.length; j++) {
                let otherInfo = invoiceOthers[j]
                let cardInfo = {
                    subjectId: otherInfo.subjectId,
                    price1: otherInfo.amount,
                    price2: 0,
                    remark: card.remark
                }
                if (j === 0) {
                    cardInfo.remark = invoice.billNo + "生成," + (otherInfo.remark ? otherInfo.remark : '')
                }
                list.push(cardInfo);
                sub1 = tools.add(sub1, otherInfo.amount)
            }
            // 贷
            for (let j = 0; j < invoiceOthers.length; j++) {
                let otherInfo = invoiceOthers[j]
                let cardInfo = {
                    subjectId: otherInfo.accId,
                    price1: 0,
                    price2: otherInfo.amount,
                    remark: card.remark
                }
                list.push(cardInfo);
            }
        }
            break;
        case 153406: {
            // 预付C
            let invoiceOthers = await db.models['invoiceOther'].findAll({
                where: {
                    iid: invoice.id
                }
            })
            let category = await getSubjectByName("预付账款", tenantId);
            // 借 预付账款
            if (tools.xe.toNumber(invoice.totalAmount) !== 0) {
                let cardInfo = {
                    subjectId: category.id,
                    price1: invoice.totalAmount,
                    price2: 0,
                    remark: "票据" + invoice.billNo + "生成" + (invoice.remark ? invoice.remark : '')
                }
                list.push(cardInfo);
            }
            // 贷
            let sub = 0;
            for (let i = 0; i < invoiceOthers.length; i++) {
                let otherInfo = invoiceOthers[i]
                let cardInfo1 = {
                    subjectId: otherInfo.accId,
                    price1: 0,
                    price2: otherInfo.amount,
                    remark: "票据" + invoice.billNo + "生成" + (invoice.remark ? invoice.remark : '')
                }
                list.push(cardInfo1)
                sub = tools.add(sub, otherInfo.amount)
            }
        }
            break;
        // 预收商品
        case 153403: {
            let yszk = await getSubjectByName("预收账款", tenantId);
            let acc = null
            if (tools.xe.toNumber(invoice.totalAmount) !== 0) {
                if (!invoice.accId) throw Error("请选择账号科目");
                acc = await getSubjectById(invoice.accId);
            }
            if (!acc) throw Error("未知账户科目");
            // 借
            let cardInfo = {
                subjectId: invoice.accId,
                price1: invoice.accAmount,
                price2: 0,
                remark: "票据" + invoice.billNo + "生成" + (invoice.remark ? invoice.remark : '')
            }
            list.push(cardInfo);
            if (invoice.accId1 && invoice.accAmount1) {
                if (tools.xe.toNumber(invoice.accAmount1) !== 0) {
                    acc = await getSubjectById(invoice.accId1);
                    if (!acc) throw Error("未知账户科目");
                    let cardInfo1 = {
                        subjectId: invoice.accId1,
                        price1: invoice.accAmount1,
                        price2: 0,
                        remark: "票据" + invoice.billNo + "生成" + (invoice.remark ? invoice.remark : '')
                    }
                    list.push(cardInfo1);
                }
            }
            // 贷 预收账款
            let cardInfo1 = {
                subjectId: yszk.id,
                price1: 0,
                price2: invoice.amount,
                remark: "票据" + invoice.billNo + "生成" + (invoice.remark ? invoice.remark : '')
            }
            list.push(cardInfo1);
        }
            break;
        // 应收
        case 153404: {
            let invoiceYsfs = await db.models['invoiceOther'].findAll({
                where: {
                    iid: invoice.id
                }
            })
            // 借应收账款
            let category = await getSubjectByName('其他应收款', tenantId)
            let cardInfo = {
                subjectId: category.id,
                price1: invoice.totalAmount,
                price2: 0,
                remark: "票据" + invoice.billNo + "生成"
            }
            list.push(cardInfo);
            // 贷
            for (let i = 0; i < invoiceYsfs.length; i++) {
                let invoiceYsf = invoiceYsfs[i]
                let cardInfo1 = {
                    subjectId: invoiceYsf.accId,
                    price1: 0,
                    price2: invoiceYsf.amount,
                    remark: "票据" + invoice.billNo + "生成"
                }
                list.push(cardInfo1);
            }
        }
            break;
        // 应付
        case 153405: {
            let invoiceYsfs = await db.models['invoiceOther'].findAll({
                where: {
                    iid: invoice.id
                }
            })
            // 借
            for (let i = 0; i < invoiceYsfs.length; i++) {
                let invoiceYsf = invoiceYsfs[i]
                let cardInfo1 = {
                    subjectId: invoiceYsf.accId,
                    price1: invoiceYsf.amount,
                    price2: 0,
                    remark: "票据" + invoice.billNo + "生成"
                }
                list.push(cardInfo1);
            }
            // 贷应付
            let category = await getSubjectByName('其他应付款', tenantId)
            let cardInfo = {
                subjectId: category.id,
                price1: 0,
                price2: invoice.totalAmount,
                remark: "票据" + invoice.billNo + "生成"
            }
            list.push(cardInfo);
        }
            break;
        // 预收
        case 153407: {
            let invoiceOthers = await db.models['invoiceOther'].findAll({
                where: {
                    iid: invoice.id
                }
            })
            let category = await getSubjectByName("预收账款", tenantId);
            // 借
            let sub = 0
            for (let i = 0; i < invoiceOthers.length; i++) {
                let otherInfo = invoiceOthers[i]
                let cardInfo = {
                    subjectId: otherInfo.accId,
                    price1: otherInfo.amount,
                    price2: 0,
                    remark: "票据" + invoice.billNo + "生成" + (otherInfo.remark ? otherInfo.remark : '')
                }
                list.push(cardInfo);
                sub = tools.xe.add(sub, otherInfo.amount)
            }
            // 贷 预收账款
            if (tools.xe.toNumber(invoice.totalAmount) !== 0) {
                let cardInfo = {
                    subjectId: category.id,
                    price1: 0,
                    price2: invoice.totalAmount,
                    remark: ''
                }
                list.push(cardInfo);
            }

        }
            break;
        case 160001: {
            let invoiceOthers = await db.models['invoiceTrans'].findAll({
                where: {
                    iid: invoice.id
                }
            })

            for (let i = 0; i < invoiceOthers.length; i++) {
                let invoiceOther = invoiceOthers[i]
                let cardInfo = {
                    subjectId: invoiceOther.accId1,
                    price1: invoiceOther.amount,
                    price2: 0,
                    remark: ("票据" + invoice.billNo + "生成" + (invoiceOther.remark ? invoiceOther.remark : ''))
                }
                list.push(cardInfo);
            }
            for (let i = 0; i < invoiceOthers.length; i++) {
                let invoiceOther = invoiceOthers[i]
                let cardInfo = {
                    subjectId: invoiceOther.accId,
                    price1: 0,
                    price2: invoiceOther.amount,
                    remark: ("票据" + invoice.billNo + "生成" + (invoiceOther.remark ? invoiceOther.remark : ''))
                }
                list.push(cardInfo);
            }
        } break;
    }

    if (list.length > 0) {
        if (list.length < 2) throw Error("至少 2 条分录");
        // 检测借贷是否相等
        isJdEqual(list);

        await db.transaction(async () => {
            let cardModel = await card.save()
            for (let i = 0; i < list.length; i++) {
                let cardInfo = list[i]
                cardInfo.byIid = cardModel.byIid
                cardInfo.cardId = cardModel.id
                cardInfo.tenantId = tenantId
            }

            // 保存凭证明细
            await db.models['cardInfo'].bulkCreate(list)

            await saveLogCard(tenantId, uid, card.id, "审核", card);
        })
    }
}

const setInvoiceGoods = async (tenantId, id ) => {
    let sqls = `
        update a set a.goods=b.goods,a.subRemark=b.subRemark from invoice a 
        inner join 
        (
            SELECT iid,string_agg(invName,',') goods,string_agg(remark, ',') subRemark  from v_main_info where iid=${id} GROUP BY iid 
        ) b on a.id=b.iid and a.tenantId=${tenantId} and a.id=${id} 
    `
    await db.query(sqls, {type: QueryTypes.UPDATE})
}


module.exports = {
    updateInventory, updateAssQty, detectStock, setBillNo,
    billCanEdit, toAccounted, saveHistPrice, detectHasReceipt, detectYsGoods,
    saveContactSales,saveContactGoods, getSubjectById,getSubjectByName,isJdEqual,saveLogCard,createCard,hxYusf,
    setInvoiceGoods
}